﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Activation;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Contexts;
using System.Runtime.Remoting.Messaging;
using System.Runtime.Remoting.Proxies;
using System.Reflection;
using Titan.Reflection;

namespace Titan.Remoting
{
    public class IDCMessageSink : IMessageSink
    {
        private static Dictionary<string, WellKnownServiceTypeEntry> _wellKnownServiceTypes;
        private static object _lock = new object();
        private static DateTime _syncTime = DateTime.MinValue;
        private static TimeSpan PollingTime = TimeSpan.FromSeconds(10);
        private static Dictionary<string, object> _singletonDict = new Dictionary<string, object>(StringComparer.CurrentCultureIgnoreCase);

        private static Dictionary<string, WellKnownServiceTypeEntry> GetRegisteredWellKnownServiceTypes()
        {
            Dictionary<string, WellKnownServiceTypeEntry> retval = new Dictionary<string, WellKnownServiceTypeEntry>(StringComparer.CurrentCultureIgnoreCase);
            foreach (WellKnownServiceTypeEntry entry in RemotingConfiguration.GetRegisteredWellKnownServiceTypes())
            {
                retval.Add(entry.ObjectUri, entry);
            }
            return retval;
        }

        //WellKnownServiceTypeEntry,将在服务端注册的对象类型的值保存为服务器激活类型对象 
        private static WellKnownServiceTypeEntry GetWellKnownServiceType(string uri)
        {
            if (null == _wellKnownServiceTypes)
            {
                lock (_lock)
                {
                    if (null == _wellKnownServiceTypes)
                    {
                        _wellKnownServiceTypes = GetRegisteredWellKnownServiceTypes();
                    }
                }
            }
            else
            {
                DateTime now = DateTime.Now;
                if ((now - _syncTime).Duration() > PollingTime)
                {
                    lock (_lock)
                    {
                        if ((now - _syncTime).Duration() > PollingTime)
                        {
                            _wellKnownServiceTypes = GetRegisteredWellKnownServiceTypes();
                            _syncTime = now;
                        }
                    }
                }
            }
            return _wellKnownServiceTypes[uri];
        }

        private IDCChannel _channel;
        private object _remoteChannelData;
        private string _objectURI;

        public IDCMessageSink(IDCChannel channel, object remoteChannelData, string objectURI)
        {
            _channel = channel;
            _remoteChannelData = remoteChannelData;
            _objectURI = objectURI;
        }

        public IMessageCtrl AsyncProcessMessage(IMessage msg, IMessageSink replySink)
        {
            throw new NotImplementedException();
        }

        public IMessageSink NextSink
        {
            get { return null; }
        }

        public IMessage SyncProcessMessage(IMessage msg)
        {
            IMethodCallMessage callMsg = msg as IMethodCallMessage;
            if (null != callMsg)
            {
                WellKnownServiceTypeEntry typeEntry = GetWellKnownServiceType(_objectURI);
                object target = null;

                if (typeEntry.Mode == WellKnownObjectMode.Singleton)
                {
                    if (!_channel.Singletons.TryGetValue(_objectURI, out target))
                    {
                        lock (_channel.Singletons)
                        {
                            if (!_channel.Singletons.TryGetValue(_objectURI, out target))
                            {
                                target = FastReflection.CreateObject(typeEntry.ObjectType);
                                _channel.Singletons.Add(_objectURI, target);
                            }
                        }
                    }
                }
                else
                {
                    target = FastReflection.CreateObject(typeEntry.ObjectType);
                }
                IMethodReturnMessage retMsg = RemotingServices.ExecuteMessage((MarshalByRefObject)target, callMsg);
                return retMsg;
            }
            return null;
        }

    }
}
